package com.gw.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.util.IdUtil;
import com.gw.mapper.UserMapper;
import com.gw.pojo.dto.UserForgetPasswordDTO;
import com.gw.pojo.dto.UserLoginDTO;
import com.gw.pojo.dto.UserRegisterDTO;
import com.gw.pojo.entity.User;
import com.gw.pojo.vo.UserLoginVO;
import com.gw.properties.JwtProperties;
import com.gw.service.UserService;
import com.gw.utils.JavaMailUntil;
import com.gw.utils.JwtUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;


@Service
public class UserServiceImpl implements UserService {


    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JavaMailUntil javaMailUntil;

    /**
     * 用户登录
     * @param userLoginDTO
     * @return
     */
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        String email = userLoginDTO.getEmail();
        String password = userLoginDTO.getPassword();

        User user = userMapper.getByEmail(email);
        if (user == null) {
            //账号不存在
            throw new RuntimeException("账号不存在");
        }

        //密码对比
        //进行md5加密再对比
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(user.getPassword())) {
            //密码错误
            throw new RuntimeException("密码错误");
        }

        return getUserLoginVO(user);
    }

    /**
     * 用户注册
     * @param userRegisterDTO
     * @return
     */
    public UserLoginVO register(UserRegisterDTO userRegisterDTO) {
        //验证邮箱验证码
        String mail = userRegisterDTO.getEmail();
        String code = userRegisterDTO.getCode();

        if (!Objects.equals(redisTemplate.opsForValue().get(mail), code)) {
            throw new RuntimeException("验证码错误！");
        }

        redisTemplate.delete(mail);

        //查询此邮箱是否已经注册
        User user1 = new User();

        user1 = userMapper.getByEmail(userRegisterDTO.getEmail());
        if (user1 != null) {
            throw new RuntimeException("用户信息已存在，请勿重复注册！");
        }

        User user = new User();

        BeanUtils.copyProperties(userRegisterDTO, user);
        user.setPassword(DigestUtils.md5DigestAsHex(userRegisterDTO.getPassword().getBytes()));
        //TODO 用户注册时填入默认头像url
        user.setAvatar("默认头像url");
        userMapper.addUser(user);
        return getUserLoginVO(user);
    }

    /**
     * 封装的登录和注册的返回方法
     * @param user
     * @return
     */
    private UserLoginVO getUserLoginVO(User user) {
        //生成token
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        String token = JwtUtil.creatJWT(
                jwtProperties.getUserSecretKey(),
                jwtProperties.getUserTtl(),
                claims);
        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .avatar(user.getAvatar())
                .nickname(user.getNickname())
                .identity(user.getIdentity())
                .token(token)
                .build();
        return userLoginVO;
    }

    /**
     * 获取图形验证码
     * @return
     */
    public ConcurrentHashMap<String, String> getCode() {

        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        String verify = IdUtil.simpleUUID();
        //图形验证码写出，可以写出到文件，也可以写出到流
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        lineCaptcha.write(os);
        String code = lineCaptcha.getCode();
//        缓存三分钟的验证码
        redisTemplate.opsForValue().set(verify, code, Duration.ofMinutes(3));
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(5);
        //验证码对应的redis上的uuid
        map.put("uuid", verify);
        //图片上的验证码
        map.put("code", code);
        //将图片转换成输出流传到前端上
        map.put("img", Base64.encode(os.toByteArray()));
        return map;
    }

    /**
     * 发送邮箱验证码
     * @param email
     */
    public void sendCode(String email) {

        //生成大小写字母数字随机验证码code
        char  [] pardStore = new char[62];
        for (int i = 0; i <26 ; i++) {
            pardStore [i] = (char)('A'+i);
        }
        for (int i = 26; i <52 ; i++) {
            pardStore [i] = (char)('a'+(i-26));
        }
        for (int i = 52; i <62 ; i++) {
            pardStore [i] = (char)('0'+(i-52));
        }
        Random r = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            int n = r.nextInt(62);
            code.append(pardStore[n]);
        }
        //	创建Session会话
        Session session = javaMailUntil.createSession();

        //	创建邮件对象
        MimeMessage message = new MimeMessage(session);
        try {
            message.setSubject("软件部落验证码");
            message.setText("您的验证码是： "+ code + "  。请妥善保管，此验证码三分钟内有效");
            message.setFrom(new InternetAddress("ruanjianbuluo@163.com"));
            message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(email));

            //	发送
            Transport.send(message);
        } catch (MessagingException e) {
            throw new RuntimeException("邮件发送失败！");
        }
        //存入redis
        redisTemplate.opsForValue().set(email, code.toString(), Duration.ofMinutes(3));
    }

    /**
     * 忘记密码
     * @param userForgetPasswordDTO
     * @return
     */
    public void forgetPassword(UserForgetPasswordDTO userForgetPasswordDTO) {
        //验证邮箱验证码
        String mail = userForgetPasswordDTO.getEmail();
        String code = userForgetPasswordDTO.getCode();

        if (!Objects.equals(redisTemplate.opsForValue().get(mail), code)) {
            throw new RuntimeException("验证码错误！");
        }
        redisTemplate.delete(mail);

        User user = new User();
        BeanUtils.copyProperties(userForgetPasswordDTO, user);

        userMapper.updateUser(user);

    }
}
